﻿using MiniFox.Caching;
using MiniFox.Components;
using MiniFox.Web;
using Wechat.MP.Auth.Configurations;
using Wechat.MP.Auth.Models;

namespace Wechat.MP.Auth.Services
{
    /// <summary>
    /// 
    /// </summary>
    public class WechatMpAuthService : WechatMpService, IWechatMpAuthService
    {
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        public WechatMpAuthService(string name) : base(name)
        {

        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="setting"></param>
        public WechatMpAuthService(IWechatClient setting) : base(setting)
        { 
        }
        /// <summary>
        /// 
        /// </summary>
        [AutoConfigure]
        protected WechatMpAuthConfiguration AuthConfiguration { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public Uri OpenAuthUri
        {
            get
            {
                return new Uri(AuthConfiguration.OpenAuthUri);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Uri QrAuthUri
        {
            get
            {
                return new Uri(AuthConfiguration.QrAuthUri);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Uri GetAuthTokenUri
        {
            get
            {
                return new Uri(AuthConfiguration.AuthTokenUri);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Uri RenewAuthTokenUri
        {
            get
            {
                return new Uri(AuthConfiguration.RenewAuthTokenUri);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Uri SessionUri
        {
            get
            {
                return new Uri(AuthConfiguration.SessionUri);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        public Uri UserInfoUri
        {
            get
            {
                return new Uri(AuthConfiguration.UserInfoUri);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="redirectUri"></param>
        /// <param name="state"></param>
        /// <param name="authMode"></param>
        /// <returns></returns>
        public virtual string CreateRedirectUri(string redirectUri, string state, AuthMode authMode)
        {
            var param = new
            {
                appid = this.AppID,
                redirect_uri = redirectUri,
                response_type = "code",
                scope = this.Setting.AuthScope,
                state = state
            };
            Uri uri = authMode switch
            {
                AuthMode.QrCode => this.QrAuthUri.AddQueryString(param),
                _ => this.OpenAuthUri.AddQueryString(param),
            };
            return uri.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="authCode"></param>
        /// <returns></returns>
        public async Task<AuthTokenResponse> CreateAuthTokenAsync(string authCode)
        {
            var param = new
            {
                appid = this.AppID,
                secret = this.Setting.SecretKey,
                code = authCode,
                grant_type = "authorization_code"
            };
            var uri = this.GetAuthTokenUri;
            uri = uri.AddQueryString(param);
            AuthTokenResponse token = await this.HttpGetAsync<AuthTokenResponse>(uri);
            if (token != null)
                CacheService.AddCacheObject(token.RefreshToken, token, token.ExpiresIn);
            return token;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="refreshToken"></param>
        /// <returns></returns>
        public async Task<AuthTokenResponse> RenewAuthTokenAsync(string refreshToken)
        {
            string key = refreshToken;
            AuthTokenResponse token = CacheService.GetCacheObject<AuthTokenResponse>(key);
            if (token == null)
            {
                token = await RefreshAuthTokenAsync(refreshToken);
                if (token != null)
                {
                    key = token.RefreshToken;
                    CacheService.AddCacheObject(key, token, token.ExpiresIn);
                }
            }
            return token;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="refreshToken"></param>
        /// <returns></returns>
        protected virtual Task<AuthTokenResponse> RefreshAuthTokenAsync(string refreshToken)
        {
            var param = new
            {
                appid = this.AppID,
                grant_type = "refresh_token",
                refresh_token = refreshToken
            };
            var uri = this.RenewAuthTokenUri.AddQueryString(param);
            return HttpGetAsync<AuthTokenResponse>(uri);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="refreshToken"></param>
        public void ResetAuthToken(string refreshToken)
        {
            string key = refreshToken;
            CacheService.RemoveObject(key);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="authCode"></param>
        /// <returns></returns>
        public Task<SessionResponse> GetSessionAsync(string authCode)
        {
            var uri = this.SessionUri.AddQueryString(new { appid = this.AppID, secret = this.Setting.SecretKey, js_code = authCode, grant_type = "authorization_code" });
            return HttpGetAsync<SessionResponse>(uri);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="authToken"></param>
        /// <returns></returns>
        public Task<UserInfoResponse> GetUserInfoAsync(AuthTokenResponse authToken)
        {
            var uri = this.UserInfoUri.AddQueryString(new { access_token = authToken.AccessToken, openid = authToken.OpenID, lang = "zh_CN" });
            return HttpGetAsync<UserInfoResponse>(uri);
        }

    }
}
